<template>
  <el-tooltip
    ref="popper"
    v-model:visible="showPicker"
    :show-arrow="false"
    :fallback-placements="['bottom', 'top', 'right', 'left']"
    :offset="0"
    :gpu-acceleration="false"
    :popper-class="['el-color-picker__panel','el-color-dropdown', popperClass]"
    :stop-popper-mouse-event="false"
    effect="light"
    trigger="click"
    transition="el-zoom-in-top"
    persistent
  >
    <template #content>
      <div v-click-outside="hide">
        <div class="el-color-dropdown__main-wrapper">
          <hue-slider ref="hue" class="hue-slider" :color="color" vertical />
          <sv-panel ref="svPanel" :color="color" />
        </div>
        <predefine
          v-if="predefine"
          ref="predefine"
          :color="color"
          :colors="predefine"
        />
        <div class="el-color-dropdown__btns">
          <span class="el-color-dropdown__value">
            <el-input
              v-model="customInput"
              :validate-event="false"
              size="small"
              @keyup.enter="handleConfirm"
              @blur="handleConfirm"
            />
          </span>
          <el-button
            class="el-color-dropdown__link-btn"
            text
            size="small"
            @click="clear"
          >
            清除
          </el-button>
          <el-button
            plain
            size="small"
            class="el-color-dropdown__btn"
            @click="confirmValue"
          >
            确认
          </el-button>
        </div>
      </div>
    </template>
    <template #default>
      <div
        class="el-color-picker el-color-picker--small"
        role="button"
        :tabindex="tabindex"
        @keydown.enter="handleTrigger"
      >
        <div class="el-color-picker__trigger" @click="handleTrigger">
          <span class="el-color-picker__color" style="border:none">
            <span
              class="el-color-picker__color-inner"
              :style="{
                fontSize:'12px',
              }"
            >
              <template v-if="$slots.icon">
                <slot name="icon"></slot>
              </template>
              <template v-else>
                <el-icon
                  v-show="modelValue || showPanelColor"
                  class="el-icon el-color-picker__icon is-icon-arrow-down"
                >
                  <arrow-down />
                </el-icon>
                <el-icon
                  v-if="!modelValue && !showPanelColor"
                  class="el-icon el-color-picker__empty is-icon-close"
                >
                  <close />
                </el-icon>
              </template>

            </span>
          </span>
        </div>
      </div>
    </template>
  </el-tooltip>
</template>

<script>
import {
  computed,
  defineComponent,
  nextTick,
  onMounted,
  provide,
  reactive,
  ref,
  watch,
} from 'vue';
import { debounce } from 'lodash-unified';

import ClickOutside from '@/directives/click-outside.js';

import { ArrowDown, Close } from '@element-plus/icons-vue';
import HueSlider from './components/hue-slider.vue';
import Predefine from './components/predefine.vue';
import SvPanel from './components/sv-panel.vue';
import Color from './color';
import { OPTIONS_KEY } from './useOption';

export default defineComponent({
  name: 'ElColorPicker',
  components: {
    Close,
    ArrowDown,
    SvPanel,
    HueSlider,
    Predefine,
  },
  directives: {
    ClickOutside,
  },
  props: {
    modelValue: String,
    showAlpha: Boolean,
    colorFormat: String,
    popperClass: String,
    label: {
      type: String,
      default: undefined,
    },
    tabindex: {
      type: [String, Number],
      default: 0,
    },
    predefine: Array,

  },
  emits: ['change', 'active-change', 'update:modelValue'],
  setup(props, { emit }) {
    const hue = ref();
    const svPanel = ref();
    const alpha = ref();
    const popper = ref(null);
    // active-change is used to prevent modelValue changes from triggering.
    let shouldActiveChange = true;
    // data
    const color = reactive(
      new Color({
        enableAlpha: props.showAlpha,
        format: props.colorFormat || '',
        value: props.modelValue,
      }),
    );
    const showPicker = ref(false);
    const showPanelColor = ref(false);
    const customInput = ref('');
    // computed
    const displayedColor = computed(() => {
      if (!props.modelValue && !showPanelColor.value) {
        return 'transparent';
      }
      return displayedRgb(color, props.showAlpha);
    });
    const colorSize = 'small';

    const currentColor = computed(() => {
      return !props.modelValue && !showPanelColor.value ? '' : color.value;
    });

    // watch
    watch(
      () => props.modelValue,
      (newVal) => {
        if (!newVal) {
          showPanelColor.value = false;
        } else if (newVal && newVal !== color.value) {
          shouldActiveChange = false;
          color.fromString(newVal);
        }
      },
    );
    watch(
      () => currentColor.value,
      (val) => {
        customInput.value = val;
        shouldActiveChange && emit('active-change', val);
        shouldActiveChange = true;
      },
    );

    watch(
      () => color.value,
      () => {
        if (!props.modelValue && !showPanelColor.value) {
          showPanelColor.value = true;
        }
      },
    );

    // methods
    function displayedRgb(color, showAlpha) {
      if (!(color instanceof Color)) {
        throw new TypeError('color should be instance of _color Class');
      }

      const { r, g, b } = color.toRgb();
      return showAlpha
        ? `rgba(${r}, ${g}, ${b}, ${color.get('alpha') / 100})`
        : `rgb(${r}, ${g}, ${b})`;
    }

    function setShowPicker(value) {
      showPicker.value = value;
    }

    const debounceSetShowPicker = debounce(setShowPicker, 100);

    function hide() {
      debounceSetShowPicker(false);
      resetColor();
    }

    function resetColor() {
      nextTick(() => {
        if (props.modelValue) {
          color.fromString(props.modelValue);
        } else {
          color.value = '';
          nextTick(() => {
            showPanelColor.value = false;
          });
        }
      });
    }

    function handleTrigger() {
      debounceSetShowPicker(!showPicker.value);
    }

    function handleConfirm() {
      color.fromString(customInput.value);
    }

    function confirmValue() {
      const value = color.value;
      emit('update:modelValue', value);
      emit('change', value);

      debounceSetShowPicker(false);
      // check if modelValue change, if not change, then reset color.
      nextTick(() => {
        const newColor = new Color({
          enableAlpha: props.showAlpha,
          format: props.colorFormat || '',
          value: props.modelValue,
        });
        if (!color.compare(newColor)) {
          resetColor();
        }
      });
    }

    function clear() {
      debounceSetShowPicker(false);
      emit('update:modelValue', null);
      emit('change', null);

      resetColor();
    }

    onMounted(() => {
      if (props.modelValue) {
        customInput.value = currentColor.value;
      }
    });
    watch(
      () => showPicker.value,
      () => {
        nextTick(() => {
          hue.value?.update();
          svPanel.value?.update();
          alpha.value?.update();
        });
      },
    );

    provide(OPTIONS_KEY, {
      currentColor,
    });

    return {
      color: color,
      colorSize,
      displayedColor,
      showPanelColor,
      showPicker,
      customInput,
      handleConfirm,
      hide,
      handleTrigger,
      clear,
      confirmValue,
      hue,
      svPanel,
      alpha,
      popper,
    };
  },
});
</script>
